package org.jeecg.config.filter;

import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.filter.FilterEventAdapter;
import com.alibaba.druid.proxy.jdbc.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jeecg.config.ParserHelpers;
import org.springframework.stereotype.Component;

import java.sql.SQLException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 数据表名转为小写
 */
@Slf4j
@Component
public class TableNamesToLowercaseFilter extends FilterEventAdapter {
    Log logger = LogFactory.getLog(getClass());

    //private final Logger logger = LoggerFactory.getLogger( this.getClass() );

    private String tableNamesToUppercase( String sql ){
        logger.info( "tableNamesToUppercase begin: - > " + sql );
        List<String> tableNames = ParserHelpers.getTablesBydruid( sql );
        logger.info( "tableNames: - > " + tableNames );
        String newSql = sql;
        if( tableNames != null ){
            Set<String> tableSet = new HashSet<String>();
            for( String tableName : tableNames ){
                //从sql语句中获取表名+前后一个字符
                String reg = "[^a-zA-Z_]"+tableName+"[^a-zA-Z_]";
                Pattern patten = Pattern.compile(reg,Pattern.CASE_INSENSITIVE);
                Matcher matcher = patten.matcher(newSql);
                while (matcher.find()){
                    tableSet.add(matcher.group());
                }
                //获取sql的最后一个匹配
                String regEnd = "[^a-zA-Z_]"+tableName+"$";
                Pattern pattenEnd = Pattern.compile(regEnd,Pattern.CASE_INSENSITIVE);
                Matcher matcherEnd = pattenEnd.matcher(newSql);
                while (matcherEnd.find()){
                    //String targetTable = matcherEnd.group().toUpperCase();
                    String targetTable = matcherEnd.group().toLowerCase();
                    newSql = newSql.replaceAll("[^a-zA-Z_]"+tableName+"$",targetTable);
                }
            }
            //把表名转为大写
            for(String table:tableSet){
                //newSql = newSql.replace(table,table.toUpperCase());
                newSql = newSql.replace(table,table.toLowerCase());
            }
        }
        logger.info( "tableNamesToUppercase end: - > " + newSql );
        return newSql;
    }

    @Override
    public CallableStatementProxy connection_prepareCall(FilterChain chain, ConnectionProxy connection, String sql ) throws SQLException, SQLException {
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.connection_prepareCall( chain, connection, sql );
    }

    @Override
    public CallableStatementProxy connection_prepareCall( FilterChain chain, ConnectionProxy connection, String sql, int resultSetType, int resultSetConcurrency ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.connection_prepareCall( chain, connection, sql, resultSetType, resultSetConcurrency );
    }

    @Override
    public CallableStatementProxy connection_prepareCall( FilterChain chain, ConnectionProxy connection, String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.connection_prepareCall( chain, connection, sql, resultSetType, resultSetConcurrency, resultSetHoldability );
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement(FilterChain chain, ConnectionProxy connection, String sql ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.connection_prepareStatement( chain, connection, sql );
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement( FilterChain chain, ConnectionProxy connection, String sql, int autoGeneratedKeys ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.connection_prepareStatement( chain, connection, sql, autoGeneratedKeys );
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement( FilterChain chain, ConnectionProxy connection, String sql, int resultSetType, int resultSetConcurrency ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.connection_prepareStatement( chain, connection, sql, resultSetType, resultSetConcurrency );
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement( FilterChain chain, ConnectionProxy connection, String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.connection_prepareStatement( chain, connection, sql, resultSetType, resultSetConcurrency, resultSetHoldability );
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement( FilterChain chain, ConnectionProxy connection, String sql, int[] columnIndexes ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.connection_prepareStatement( chain, connection, sql, columnIndexes );
    }

    @Override
    public PreparedStatementProxy connection_prepareStatement( FilterChain chain, ConnectionProxy connection, String sql, String[] columnNames ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.connection_prepareStatement( chain, connection, sql, columnNames );
    }

    @Override
    public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.statement_execute( chain, statement, sql );
    }

    @Override
    public boolean statement_execute( FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.statement_execute( chain, statement, sql, autoGeneratedKeys );
    }

    @Override
    public boolean statement_execute( FilterChain chain, StatementProxy statement, String sql, int[] columnIndexes ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.statement_execute( chain, statement, sql, columnIndexes );
    }

    @Override
    public boolean statement_execute( FilterChain chain, StatementProxy statement, String sql, String[] columnNames ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.statement_execute( chain, statement, sql, columnNames );
    }

    @Override
    public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.statement_executeQuery( chain, statement, sql );
    }

    @Override
    public int statement_executeUpdate( FilterChain chain, StatementProxy statement, String sql ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.statement_executeUpdate( chain, statement, sql );
    }

    @Override
    public int statement_executeUpdate( FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.statement_executeUpdate( chain, statement, sql, autoGeneratedKeys );
    }

    @Override
    public int statement_executeUpdate( FilterChain chain, StatementProxy statement, String sql, int[] columnIndexes ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.statement_executeUpdate( chain, statement, sql, columnIndexes );
    }

    @Override
    public int statement_executeUpdate( FilterChain chain, StatementProxy statement, String sql, String[] columnNames ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        return super.statement_executeUpdate( chain, statement, sql, columnNames );
    }

    /**
     * 添加批处理sql
     * @param chain
     * @param statement
     * @param sql
     * @throws SQLException
     */
    @Override
    public void statement_addBatch( FilterChain chain, StatementProxy statement, String sql ) throws SQLException{
        logger.info( sql );
        sql = this.tableNamesToUppercase( sql );
        super.statement_addBatch( chain, statement, sql );
    }


    @Override
    protected void statementExecuteQueryBefore( StatementProxy statement, String sql ){
        logger.info( sql );
    }

    @Override
    protected void statementExecuteUpdateBefore( StatementProxy statement, String sql ){
        logger.info( sql );
    }

    @Override
    protected void statementExecuteBefore( StatementProxy statement, String sql ){
        logger.info( sql );
    }

    @Override
    protected void statementExecuteBatchBefore( StatementProxy statement ){
    }
}
